/*
 * Configuration defaults
 *
 * DO NOT EDIT THIS FILE!
 *
 * You can override every macro defined in this file
 * by defining a macro of the same name in config.h.
 * See docs/build.md for details.
 *
 * Copyright 2022 and 2023 Odin Kroeger.
 *
 * This file is part of suCGI.
 *
 * suCGI is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * suCGI is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General
 * Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with suCGI. If not, see <https://www.gnu.org/licenses/>.
 */

#if !defined(PARAMS_H)
#define PARAMS_H

#include <sys/stat.h>
#include <limits.h>
#include <stdint.h>
#include <syslog.h>

#include "config.h"


/*
 * Test suite configuration
 */

#if defined(TESTING) && TESTING

#undef USER_DIR
#define USER_DIR "/tmp/sucgi-check/%n"

#undef SAFE_ENV_VARS
#define SAFE_ENV_VARS { \
    "^DYLD_INSERT_LIBRARIES$", \
    "^LD_PRELOAD$", \
    "^GCOV_PREFIX$", \
    "^GCOV_PREFIX_STRIP$", \
    "^AUTH_TYPE$", \
    "^CONTENT_LENGTH$", \
    "^CONTENT_TYPE$", \
    "^CONTEXT_DOCUMENT_ROOT$", \
    "^CONTEXT_PREFIX$", \
    "^DATE_GMT$", \
    "^DATE_LOCAL$", \
    "^DOCUMENT_NAME$", \
    "^DOCUMENT_PATH_INFO$", \
    "^DOCUMENT_URI$", \
    "^GATEWAY_INTERFACE$", \
    "^HANDLER$", \
    "^HTTP_ACCEPT$", \
    "^HTTP_COOKIE$", \
    "^HTTP_FORWARDED$", \
    "^HTTP_HOST$", \
    "^HTTP_PROXY_CONNECTION$", \
    "^HTTP_REFERER$", \
    "^HTTP_USER_AGENT$", \
    "^HTTP2$", \
    "^HTTPS$", \
    "^IS_SUBREQ$", \
    "^IPV6$", \
    "^LAST_MODIFIED$", \
    "^PATH_INFO$", \
    "^PATH_TRANSLATED$", \
    "^QUERY_STRING$", \
    "^QUERY_STRING_UNESCAPED$", \
    "^REMOTE_ADDR$", \
    "^REMOTE_HOST$", \
    "^REMOTE_IDENT$", \
    "^REMOTE_PORT$", \
    "^REMOTE_USER$", \
    "^REDIRECT_ERROR_NOTES$", \
    "^REDIRECT_HANDLER$", \
    "^REDIRECT_QUERY_STRING$", \
    "^REDIRECT_REMOTE_USER$", \
    "^REDIRECT_SCRIPT_FILENAME$", \
    "^REDIRECT_STATUS$", \
    "^REDIRECT_URL$", \
    "^REQUEST_LOG_ID$", \
    "^REQUEST_METHOD$", \
    "^REQUEST_SCHEME$", \
    "^REQUEST_STATUS$", \
    "^REQUEST_URI$", \
    "^SCRIPT_FILENAME$", \
    "^SCRIPT_NAME$", \
    "^SCRIPT_URI$", \
    "^SCRIPT_URL$", \
    "^SERVER_ADMIN$", \
    "^SERVER_NAME$", \
    "^SERVER_ADDR$", \
    "^SERVER_PORT$", \
    "^SERVER_PROTOCOL$", \
    "^SERVER_SIGNATURE$", \
    "^SERVER_SOFTWARE$", \
    "^SSL_CIPHER$", \
    "^SSL_CIPHER_EXPORT$", \
    "^SSL_CIPHER_USEKEYSIZE$", \
    "^SSL_CIPHER_ALGKEYSIZE$", \
    "^SSL_CLIENT_M_VERSION$", \
    "^SSL_CLIENT_M_SERIAL$", \
    "^SSL_CLIENT_S_DN$", \
    "^SSL_CLIENT_S_DN_(C|ST|L|O|OU|CN|T|I|G|S|D|UID|Email)$", \
    "^SSL_CLIENT_S_DN_(C|ST|L|O|OU|CN|T|I|G|S|D|UID|Email)_(0|[1-9][0-9]*)$", \
    "^SSL_CLIENT_SAN_Email_(0|[1-9][0-9]*)$", \
    "^SSL_CLIENT_SAN_DNS_(0|[1-9][0-9]*)$", \
    "^SSL_CLIENT_SAN_OTHER_msUPN_(0|[1-9][0-9]*)$", \
    "^SSL_CLIENT_I_DN$", \
    "^SSL_CLIENT_I_DN_(C|ST|L|O|OU|CN|T|I|G|S|D|UID|Email)$", \
    "^SSL_CLIENT_I_DN_(C|ST|L|O|OU|CN|T|I|G|S|D|UID|Email)_(0|[1-9][0-9]*)$", \
    "^SSL_CLIENT_V_START$", \
    "^SSL_CLIENT_V_END$", \
    "^SSL_CLIENT_V_REMAIN$", \
    "^SSL_CLIENT_A_SIG$", \
    "^SSL_CLIENT_A_KEY$", \
    "^SSL_CLIENT_CERT$", \
    "^SSL_CLIENT_CERT_CHAIN_(0|[1-9][0-9]*)$", \
    "^SSL_CLIENT_CERT_RFC4523_CEA$", \
    "^SSL_CLIENT_VERIFY$", \
    "^SSL_COMPRESS_METHOD$", \
    "^SSL_PROTOCOL$", \
    "^SSL_SECURE_RENEG$", \
    "^SSL_SERVER_M_VERSION$", \
    "^SSL_SERVER_M_SERIAL$", \
    "^SSL_SERVER_S_DN_(C|ST|L|O|OU|CN|T|I|G|S|D|UID|Email)$", \
    "^SSL_SERVER_S_DN_(C|ST|L|O|OU|CN|T|I|G|S|D|UID|Email)_(0|[1-9][0-9]*)$", \
    "^SSL_SERVER_SAN_Email_(0|[1-9][0-9]*)$", \
    "^SSL_SERVER_SAN_DNS_(0|[1-9][0-9]*)$", \
    "^SSL_SERVER_SAN_OTHER_dnsSRV_(0|[1-9][0-9]*)$", \
    "^SSL_SERVER_I_DN_(C|ST|L|O|OU|CN|T|I|G|S|D|UID|Email)$", \
    "^SSL_SERVER_I_DN_(C|ST|L|O|OU|CN|T|I|G|S|D|UID|Email)_(0|[1-9][0-9]*)$", \
    "^SSL_SERVER_V_START$", \
    "^SSL_SERVER_V_END$", \
    "^SSL_SERVER_A_SIG$", \
    "^SSL_SERVER_A_KEY$", \
    "^SSL_SERVER_CERT$", \
    "^SSL_SESSION_ID$", \
    "^SSL_SESSION_RESUMED$", \
    "^SSL_SRP_USER$", \
    "^SSL_SRP_USERINFO$", \
    "^SSL_TLS_SNI$", \
    "^SSL_VERSION_INTERFACE$", \
    "^SSL_VERSION_LIBRARY$", \
    "^UNIQUE_ID$", \
    "^USER_NAME$", \
    "^THE_REQUEST$", \
    "^TIME_YEAR$", \
    "^TIME_MON$", \
    "^TIME_DAY$", \
    "^TIME_HOUR$", \
    "^TIME_MIN$", \
    "^TIME_SEC$", \
    "^TIME_WDAY$", \
    "^TIME$", \
    "^TMPDIR$", \
    "^TZ$" \
}

#undef SCRIPT_HANDLERS
#define SCRIPT_HANDLERS {{".sh", "sh"}, {".empty", ""}}

#undef SYSLOG_FACILITY
#define SYSLOG_FACILITY LOG_USER

#undef SYSLOG_MASK
#define SYSLOG_MASK LOG_UPTO(LOG_DEBUG)

#undef SYSLOG_OPTS
#ifdef LOG_PERROR
#define SYSLOG_OPTS (LOG_CONS | LOG_PERROR)
#else
#define SYSLOG_OPTS LOG_CONS
#endif

#endif /* defined(TESTING) && TESTING */


/*
 * System-specific headers
 */

/* BSDs, Minix, and Illumos */
#if defined(__DragonFly__)  || \
    defined(__FreeBSD__)    || \
    defined(__NetBSD__)     || \
    defined(__OpenBSD__)    || \
    defined(__MACH__)       || \
    defined(__minix)        || \
    defined(__illumos__)

#if !defined(HAVE_SYS_PARAM_H)
#define HAVE_SYS_PARAM_H 1
#endif

#if !defined(HAVE_FEATURES_H)
#define HAVE_FEATURES_H 0
#endif

#endif /* BSD systems */

/* GNU and GNU-like systems */
#if defined(__GLIBC__)       || \
    defined(__GNU_LIBRARY__) || \
    defined(__UCLIBC__)

#if !defined(HAVE_SYS_PARAM_H)
#define HAVE_SYS_PARAM_H 1
#endif

#if !defined(HAVE_FEATURES_H)
#define HAVE_FEATURES_H 1
#endif

#endif /* GNU systems */

/* Include sys/param.h if it should be available */
#if defined(HAVE_SYS_PARAM_H) && HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif

/* Include features.h if it should be available */
#if defined(HAVE_FEATURES_H) && HAVE_FEATURES_H
#include <features.h>
#endif

/* Include features.h and sys/param.h in a round-about way, just in case */
#include <limits.h>


/*
 * Data types
 */

/* Type that getgrouplist takes and returns group IDs as */
#if !defined(GRP_T)
#if defined(__MACH__) && __MACH__
#define GRP_T int
#define MAX_GRP_VAL INT_MAX
#else
#define GRP_T gid_t
#endif
#endif

/* Type that setgroups takes the number of groups as */
#if !defined(NGRPS_T)
#if defined(__linux__) && __linux__
#define NGRPS_T size_t
#define MAX_NGRPS_VAL SIZE_MAX
#else
#define NGRPS_T int
#define MAX_NGRPS_VAL INT_MAX
#endif
#endif


/*
 * System limits
 */

/*
 * If maximum values are calculated with MAXSVAL, as opposed to having been
 * detected by ./configure, then those values will be too large if integer
 * types are padded on the target architecture. However, integer types are
 * unpadded on most architectures, including x86, x86-64, ARM, and ARM64.
 */

/* Maximum value of uid_t */
#if !defined(MAX_UID_VAL)
#define MAX_UID_VAL MAXSVAL(uid_t)
#endif

/* Maximum value of gid_t */
#if !defined(MAX_GID_VAL)
#define MAX_GID_VAL MAXSVAL(gid_t)
#endif

/* Maximum value of GRP_T */
#if !defined(MAX_GRP_VAL)
#define MAX_GRP_VAL MAXSVAL(GRP_T)
#endif

/* Maximum value of NGRPS_T */
#if !defined(MAX_NGRPS_VAL)
#define MAX_NGRPS_VAL MAXSVAL(NGRPS_T)
#endif


/*
 * Configuration defaults
 */

/*
 * The document root of user websites. Filename pattern.
 * CGI scripts are only run if they reside under their owner's document root.
 *
 * MUST correspond to the user directory set in your web server configuration.
 *
 * The following format specifiers are expanded:
 *      %n  Login name
 *      %d  Home directory
 *      %u  User ID
 *      %g  Primary group ID
 *      %%  Literal "%"
 */
#if !defined(USER_DIR)
#define USER_DIR "%d/public_html"
#endif


/*
 * The base URL of user homepages, without the hostname. Filename pattern.
 * Use "/~%n" for Apache.
 *
 * Format specifiers are the same as for USER_DIR.
 */
#if !defined(BASE_URL)
#define BASE_URL "/~%n"
#endif


/*
 * Range of user IDs reserverd for non-system users. Integers.
 *
 * Usually starts at 100, 500, or 1,000 and ends at 30,000 or 60,000.
 * [START_UID, STOP_UID] MUST be set to a subset of that range.
 *
 * Only CGI scripts owned by non-system users are executed by suCGI.
 */
#if !defined(START_UID)
#if defined(__illumos__) || defined(__sun)
#define START_UID 100
#elif defined(__MACH__)
#define START_UID 500
#else
#define START_UID 1000
#endif
#endif

#if START_UID < 1
#error START_UID must be greater than 0.
#endif

#if defined(MINUID) && START_UID < MINUID
#error START_UID must be greater than MINUID.
#endif

#if !defined(STOP_UID)
#if defined(__OpenBSD__)
#define STOP_UID 30000
#else
#define STOP_UID 60000
#endif
#endif

#if STOP_UID < START_UID
#error STOP_UID is smaller than START_UID.
#endif

#if STOP_UID > (INT_MAX - 1)
#error STOP_UID is greater than (INT_MAX - 1).
#endif

#if defined(MAXUID) && STOP_UID > MAXUID
#error STOP_UID is greater than MAXUID.
#endif


/*
 * Range of group IDs reserved for non-system groups. Integers.
 *
 * Usually starts at 100, 500, or 1,000 and ends at 30,000 or 60,000.
 * [START_GID, STOP_GID] MUST be set to a subset of that range.
 *
 * On systems that make no such reservation,
 * exclude as many system groups as feasible.
 *
 * Only CGI scripts owned by users who are NOT a member of
 * any system group are executed are suCGI.
 */
#if !defined(START_GID)
#if defined(__MACH__) || defined(__illumos__) || defined(__sun)
#define START_GID 1
#elif defined(__NetBSD__)
#define START_GID 100
#else
#define START_GID START_UID
#endif
#endif

#if START_GID < 1
#error START_GID must be greater than 0.
#endif

#if defined(MINGID) && START_GID <= MINGID
#error START_GID must be greater than MINGID.
#endif

#if !defined(STOP_GID)
#define STOP_GID STOP_UID
#endif

#if STOP_GID < START_GID
#error STOP_GID is smaller than START_GID.
#endif

#if STOP_GID > (INT_MAX - 1)
#error STOP_GID is greater than (INT_MAX - 1).
#endif

#if defined(MAXGID) && STOP_GID > MAXGID
#error STOP_GID is greater than MAXGID.
#endif

#if defined(NOGROUP) && NOGROUP > -1 && STOP_GID >= NOGROUP
#error STOP_GID is greater than or equal to NOGROUP.
#endif


/*
 * Path of the PHP-CGI executable.
 * Searched for in PATH, unless it contains a slash.
 * Keep in mind that $PATH is set to PATH (see below).
 */
#if !defined(PHP)
#define PHP "php-cgi"
#endif


/*
 * Handlers to run CGI scripts with.
 * Array of filename suffix-script handler pairs.
 *
 * The filename suffix must include the leading dot (e.g., ".php").
 * The script handler is search for in $PATH,
 * unless its name contains a slash (e.g., "php").
 * Keep in mind that $PATH is set to PATH (see below).
 *
 * If no handler can be found, suCGI will execute the CGI script directly.
 */
#if !defined(SCRIPT_HANDLERS)
#define SCRIPT_HANDLERS { \
    {".php",   PHP}, \
    {".php8",  PHP}, \
    {".php7",  PHP}, \
    {".php5",  PHP}, \
    {".php4",  PHP}, \
    {".php3",  PHP}, \
    {".phtml", PHP}, \
}
#endif


/*
 * Secure $PATH. String literal. Colon-separated list of directories.
 */
#if !defined(PATH)
#define PATH "/usr/bin:/bin"
#endif


/*
 * Secure file permission mask. Unsigned integer.
 *
 * If you give the permission mask as octal number (e.g., 022 for go-w), keep
 * in mind that numbers must be prefixed with a zero (i.e., match /^0[0-9]+/)
 * for them to be interpreted as octal by by the C compiler.
 */
#if !defined(UMASK)
#define UMASK (S_ISUID | S_ISGID | S_ISVTX | S_IRWXG | S_IRWXO)
#endif


/*
 * Environment variables to keep. Array of POSIX extended regular expressions.
 * Only variables the names of which match at least one expression are kept.
 *
 * The default list of permitted variables has been adopted from:
 *
 *     - RFC 3876 "The Common Gateway Interface (CGI) Version 1.1"
 *       <https://datatracker.ietf.org/doc/html/rfc3875>
 *     - Kira Matrejek, CGI Programming 101, chap. 3
 *       <http://www.cgi101.com/book/ch3/text.html>
 *     - Apache's suEXEC
 *       <https://github.com/apache/httpd/blob/trunk/support/suexec.c>
 *     - the Apache v2.4 variable documentation
 *       <https://httpd.apache.org/docs/2.4/expr.html#vars>
 *     - the Apache v2.4 mod_ssl documentation
 *       <https://httpd.apache.org/docs/2.4/mod/mod_ssl.html>
 *
 * MUST contain a regular expression that matches "PATH_TRANSLATED".
 *
 * Some variables are set by suCGI:
 *     - DOCUMENT_ROOT
 *     - HOME
 *     - PATH
 *     - SCRIPT_FILENAME
 *     - USER_NAME
 *
 * These variables will be set regardless of whether they match a pattern.
 *
 * There should be no need to adapt this list.
 */
#if !defined(SAFE_ENV_VARS)
#define SAFE_ENV_VARS { \
    "^AUTH_TYPE$", \
    "^CONTENT_LENGTH$", \
    "^CONTENT_TYPE$", \
    "^CONTEXT_DOCUMENT_ROOT$", \
    "^CONTEXT_PREFIX$", \
    "^DATE_GMT$", \
    "^DATE_LOCAL$", \
    "^DOCUMENT_NAME$", \
    "^DOCUMENT_PATH_INFO$", \
    "^DOCUMENT_URI$", \
    "^GATEWAY_INTERFACE$", \
    "^HANDLER$", \
    "^HTTP_ACCEPT$", \
    "^HTTP_COOKIE$", \
    "^HTTP_FORWARDED$", \
    "^HTTP_HOST$", \
    "^HTTP_PROXY_CONNECTION$", \
    "^HTTP_REFERER$", \
    "^HTTP_USER_AGENT$", \
    "^HTTP2$", \
    "^HTTPS$", \
    "^IS_SUBREQ$", \
    "^IPV6$", \
    "^LAST_MODIFIED$", \
    "^PATH_INFO$", \
    "^PATH_TRANSLATED$", \
    "^QUERY_STRING$", \
    "^QUERY_STRING_UNESCAPED$", \
    "^REMOTE_ADDR$", \
    "^REMOTE_HOST$", \
    "^REMOTE_IDENT$", \
    "^REMOTE_PORT$", \
    "^REMOTE_USER$", \
    "^REDIRECT_ERROR_NOTES$", \
    "^REDIRECT_HANDLER$", \
    "^REDIRECT_QUERY_STRING$", \
    "^REDIRECT_REMOTE_USER$", \
    "^REDIRECT_SCRIPT_FILENAME$", \
    "^REDIRECT_STATUS$", \
    "^REDIRECT_URL$", \
    "^REQUEST_LOG_ID$", \
    "^REQUEST_METHOD$", \
    "^REQUEST_SCHEME$", \
    "^REQUEST_STATUS$", \
    "^REQUEST_URI$", \
    "^SCRIPT_FILENAME$", \
    "^SCRIPT_NAME$", \
    "^SCRIPT_URI$", \
    "^SCRIPT_URL$", \
    "^SERVER_ADMIN$", \
    "^SERVER_NAME$", \
    "^SERVER_ADDR$", \
    "^SERVER_PORT$", \
    "^SERVER_PROTOCOL$", \
    "^SERVER_SIGNATURE$", \
    "^SERVER_SOFTWARE$", \
    "^SSL_CIPHER$", \
    "^SSL_CIPHER_EXPORT$", \
    "^SSL_CIPHER_USEKEYSIZE$", \
    "^SSL_CIPHER_ALGKEYSIZE$", \
    "^SSL_CLIENT_M_VERSION$", \
    "^SSL_CLIENT_M_SERIAL$", \
    "^SSL_CLIENT_S_DN$", \
    "^SSL_CLIENT_S_DN_(C|ST|L|O|OU|CN|T|I|G|S|D|UID|Email)$", \
    "^SSL_CLIENT_S_DN_(C|ST|L|O|OU|CN|T|I|G|S|D|UID|Email)_(0|[1-9][0-9]*)$", \
    "^SSL_CLIENT_SAN_Email_(0|[1-9][0-9]*)$", \
    "^SSL_CLIENT_SAN_DNS_(0|[1-9][0-9]*)$", \
    "^SSL_CLIENT_SAN_OTHER_msUPN_(0|[1-9][0-9]*)$", \
    "^SSL_CLIENT_I_DN$", \
    "^SSL_CLIENT_I_DN_(C|ST|L|O|OU|CN|T|I|G|S|D|UID|Email)$", \
    "^SSL_CLIENT_I_DN_(C|ST|L|O|OU|CN|T|I|G|S|D|UID|Email)_(0|[1-9][0-9]*)$", \
    "^SSL_CLIENT_V_START$", \
    "^SSL_CLIENT_V_END$", \
    "^SSL_CLIENT_V_REMAIN$", \
    "^SSL_CLIENT_A_SIG$", \
    "^SSL_CLIENT_A_KEY$", \
    "^SSL_CLIENT_CERT$", \
    "^SSL_CLIENT_CERT_CHAIN_(0|[1-9][0-9]*)$", \
    "^SSL_CLIENT_CERT_RFC4523_CEA$", \
    "^SSL_CLIENT_VERIFY$", \
    "^SSL_COMPRESS_METHOD$", \
    "^SSL_PROTOCOL$", \
    "^SSL_SECURE_RENEG$", \
    "^SSL_SERVER_M_VERSION$", \
    "^SSL_SERVER_M_SERIAL$", \
    "^SSL_SERVER_S_DN_(C|ST|L|O|OU|CN|T|I|G|S|D|UID|Email)$", \
    "^SSL_SERVER_S_DN_(C|ST|L|O|OU|CN|T|I|G|S|D|UID|Email)_(0|[1-9][0-9]*)$", \
    "^SSL_SERVER_SAN_Email_(0|[1-9][0-9]*)$", \
    "^SSL_SERVER_SAN_DNS_(0|[1-9][0-9]*)$", \
    "^SSL_SERVER_SAN_OTHER_dnsSRV_(0|[1-9][0-9]*)$", \
    "^SSL_SERVER_I_DN_(C|ST|L|O|OU|CN|T|I|G|S|D|UID|Email)$", \
    "^SSL_SERVER_I_DN_(C|ST|L|O|OU|CN|T|I|G|S|D|UID|Email)_(0|[1-9][0-9]*)$", \
    "^SSL_SERVER_V_START$", \
    "^SSL_SERVER_V_END$", \
    "^SSL_SERVER_A_SIG$", \
    "^SSL_SERVER_A_KEY$", \
    "^SSL_SERVER_CERT$", \
    "^SSL_SESSION_ID$", \
    "^SSL_SESSION_RESUMED$", \
    "^SSL_SRP_USER$", \
    "^SSL_SRP_USERINFO$", \
    "^SSL_TLS_SNI$", \
    "^SSL_VERSION_INTERFACE$", \
    "^SSL_VERSION_LIBRARY$", \
    "^UNIQUE_ID$", \
    "^USER_NAME$", \
    "^THE_REQUEST$", \
    "^TIME_YEAR$", \
    "^TIME_MON$", \
    "^TIME_DAY$", \
    "^TIME_HOUR$", \
    "^TIME_MIN$", \
    "^TIME_SEC$", \
    "^TIME_WDAY$", \
    "^TIME$", \
    "^TMPDIR$", \
    "^TZ$" \
}
#endif


/*
 * Priorities to log. Syslog constant.
 * See syslog(3) for details.
 */
#if !defined(SYSLOG_MASK)
#define SYSLOG_MASK LOG_UPTO(LOG_ERR)
#endif


/*
 * Facility to log to.
 * See syslog(3) for details.
 */
#if !defined(SYSLOG_FACILITY)
#define SYSLOG_FACILITY LOG_AUTH
#endif


/*
 * Syslog options.
 * See syslog(3) for details.
 */
#if !defined(SYSLOG_OPTS)
#define SYSLOG_OPTS LOG_CONS
#endif


/*
 * suCGI Limits
 */

/*
 * Maximum length for strings, including the null terminator. Unsigned integer.
 * Upper limit for all other character limits.
 */
#if !defined(MAX_STR_LEN)
#define MAX_STR_LEN 8192U
#endif

#if MAX_STR_LEN < 1
#error MAX_STR_LEN is non-positive.
#endif

#if MAX_STR_LEN > PTRDIFF_MAX
#error MAX_STR_LEN is greater than PTRDIFF_MAX.
#endif

#if MAX_STR_LEN > SHRT_MAX
#error MAX_STR_LEN is greater than SHRT_MAX.
#endif

#if MAX_STR_LEN > SIZE_MAX
#error MAX_STR_LEN is greater than SIZE_MAX.
#endif

#if MAX_STR_LEN < _POSIX_LOGIN_NAME_MAX
#error MAX_STR_LEN is smaller than _POSIX_LOGIN_NAME_MAX
#endif


/*
 * Maximum length for error message formats and error messages,
 * including the null terminator. Unsigned integer.
 */
#if !defined(MAX_ERRMSG_LEN)
#define MAX_ERRMSG_LEN 512U
#endif

#if MAX_ERRMSG_LEN < 256
#error MAX_ERRMSG_LEN is too short.
#endif

#if MAX_ERRMSG_LEN > MAX_STR_LEN
#error MAX_ERRMSG_LEN is greater than MAX_STR_LEN.
#endif

#if MAX_ERRMSG_LEN < 1
#error MAX_ERRMSG_LEN is non-positive.
#endif


/*
 * Maximum length for filenames, including the null terminator.
 * Unsigned integer. Longer filenames are rejected.
 */
#if !defined(MAX_FNAME_LEN)
#if defined(PATH_MAX) && PATH_MAX > -1
#if PATH_MAX < MAX_STR_LEN
#define MAX_FNAME_LEN PATH_MAX
#else
#define MAX_FNAME_LEN MAX_STR_LEN
#endif
#elif defined(MAXPATHLEN)
#if MAXPATHLEN < MAX_STR_LEN
#define MAX_FNAME_LEN MAXPATHLEN
#else
#define MAX_FNAME_LEN MAX_STR_LEN
#endif
#else
#define MAX_FNAME_LEN 4096
#endif
#endif

#if MAX_FNAME_LEN < 255
#error MAX_FNAME_LEN is smaller than 255.
#endif

#if MAX_FNAME_LEN < _POSIX_PATH_MAX
#error MAX_FNAME_LEN is smaller than _POSIX_PATH_MAX.
#endif

#if defined(MAXPATHLEN) && MAX_FNAME_LEN > MAXPATHLEN
#error MAX_FNAME_LEN is greater than MAXPATHLEN.
#endif

#if MAX_FNAME_LEN > MAX_STR_LEN
#error MAX_FNAME_LEN is greater than MAX_STR_LEN.
#endif

#if MAX_FNAME_LEN < 1
#error MAX_FNAME_LEN is non-positive.
#endif

/*
 * Maximum length for login names.
 * Unsigned integer. Longer usernames are rejected.
 */

#if defined(LOGIN_NAME_MAX)
#if LOGIN_NAME_MAX < MAX_STR_LEN
#define MAX_LOGNAME_LEN LOGIN_NAME_MAX
#else
#define MAX_LOGNAME_LEN MAX_STR_LEN
#endif /* LOGIN_NAME_MAX < MAX_STR_LEN */
#else
#define MAX_LOGNAME_LEN 256U
#endif /* defined(LOGIN_NAME_MAX) */


/*
 * Maximum length for filename suffices, including the null terminator.
 * Unsigned integer. Filenames with longer suffices are rejected.
 */
#if !defined(MAX_SUFFIX_LEN)
#define MAX_SUFFIX_LEN 16U
#endif

#if MAX_SUFFIX_LEN < 8
#error MAX_SUFFIX_LEN is smaller than 8.
#endif

#if MAX_SUFFIX_LEN > MAX_STR_LEN
#error MAX_SUFFIX_LEN is greater than MAX_STR_LEN.
#endif

#if MAX_SUFFIX_LEN < 1
#error MAX_SUFFIX_LEN is non-positive.
#endif


/*
 * Maximum length for URLs, including the null terminator.
 * Unsigned integer. Requests with longer URLs will be rejected.
 */
#if !defined(MAX_URL_LEN)
/* RFC 9110, sec. 4.1, mandates that URLs up to 8000 octets must be handled */
#if MAX_STR_LEN > 8192
#define MAX_URL_LEN 8192U
#else
#define MAX_URL_LEN MAX_STR_LEN
#endif /* MAX_STR_LEN > 8192 */
#else
#if MAX_URL_LEN > MAX_STR_LEN
#error MAX_URL_LEN is greater than MAX_STR_LEN.
#endif /* MAX_URL_LEN > MAX_STR_LEN */
#endif /* !defined(MAX_URL_LEN) */


/*
 * Maximum length for environment variables, including the null terminator.
 * Unsigned integer. Longer variables are ignored.
 */
#if !defined(MAX_VAR_LEN)
#define MAX_VAR_LEN MAX_FNAME_LEN
#endif

#if MAX_VAR_LEN < MAX_FNAME_LEN
#error MAX_VAR_LEN is smaller than MAX_FNAME_LEN.
#endif

#if MAX_VAR_LEN > MAX_STR_LEN
#error MAX_VAR_LEN is greater than MAX_STR_LEN.
#endif

#if MAX_VAR_LEN < 1
#error MAX_VAR_LEN is non-positive.
#endif


/*
 * Maximum length for environment variable names, including the null
 * terminator. Unsigned integer. Variables with longer names are ignored.
 */
#if !defined(MAX_VARNAME_LEN)
#define MAX_VARNAME_LEN 64U
#endif

#if MAX_VARNAME_LEN < 32
#error MAX_VARNAME_LEN is smaller than 32.
#endif

#if MAX_VARNAME_LEN > MAX_STR_LEN
#error MAX_VARNAME_LEN is greater than MAX_STR_LEN.
#endif


/*
 * Maximum number of groups a user may be a member of. Unsigned integer.
 * Users who are members of more groups are rejected.
 */
#if !defined(MAX_NGROUPS)
#define MAX_NGROUPS 256U
#endif

#if MAX_NGROUPS < 1
#error MAX_NGROUPS is non-positive.
#endif

#if MAX_NGROUPS > INT_MAX
#error MAX_NGROUPS is greater than INT_MAX.
#endif


/*
 * Maximum number of environment variables. Unsigned integer.
 * If the environment contains more variables, a run-time error is raised.
 */
#if !defined(MAX_NVARS)
#define MAX_NVARS 512
#endif

#if MAX_NVARS < 32
#error MAX_NVARS is smaller than 32.
#endif

#if MAX_NVARS > SHRT_MAX
#error MAX_NVARS is greater than SHRT_MAX.
#endif


/*
 * System
 */

/* Invalid GID to initialise memory with */
#if !defined(NOGROUP)
#define NOGROUP MAX_GID_VAL
#endif

/* Name of the standard library */
#if defined(__GLIBC__) || defined(__GNU_LIBRARY__)
#define LIBC "glibc"
#elif defined(__KLIBC__)
#define LIBC "klibc"
#elif defined(__UCLIBC__)
#define LIBC "uClibc"
#elif defined(__DragonFly__)
#define LIBC "DragonFly"
#elif defined(__FreeBSD__)
#define LIBC "FreeBSD"
#elif defined(__NetBSD__)
#define LIBC "NetBSD"
#elif defined(__OpenBSD__)
#define LIBC "OpenBSD"
#elif defined(__MACH__)
#define LIBC "Apple"
#endif


#endif /* !defined(PARAMS_H) */
